/*
 * Copyright (C) 2016 Piotr Wittchen
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.pwittchen.reactivenetwork.library.rx2;

import com.github.pwittchen.reactivenetwork.library.rx2.model.NetworkState;
import com.github.pwittchen.reactivenetwork.library.rx2.utils.Log;

import io.reactivex.rxjava3.annotations.NonNull;

import ohos.app.Context;

import ohos.net.NetCapabilities;
import ohos.net.NetManager;

import java.util.Objects;

import static com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork.LOG_TAG;

/**
 * Connectivity class represents current connectivity status. It wraps NetworkInfo object.
 */
public final class Connectivity {
    private boolean isAvailable; // NOPMD
    private boolean isRoaming; // NOPMD
    private NetworkState networkState;

    private Connectivity(Builder builder) {
        networkState = builder.networkState;
        isAvailable = builder.isAvailable;
        isRoaming = builder.isRoaming;
    }

    private Connectivity() {
        this(builder());
    }

    public static Connectivity create() {
        Connectivity connectivity = builder().build();
        return connectivity;
    }

    public static Connectivity create(@NonNull Context context, NetworkState networkState) {
        Preconditions.checkNotNull(context, "context == null");
        return create(context, getConnectivityManager(context), networkState);
    }

    protected static Connectivity create(@NonNull Context context, NetManager manager, NetworkState networkState) {
        Preconditions.checkNotNull(context, "context == null");

        if (manager == null) {
            return create();
        }
        networkState.setNetworkCapabilities(manager.getNetCapabilities(networkState.getNetHandle()));
        networkState.setLinkProperties(manager.getConnectionProperties(networkState.getNetHandle()));
        return create(networkState);
    }

    private static Connectivity create(NetworkState networkState) {
        return new Builder().networkState(networkState).build();
    }

    private static NetManager getConnectivityManager(Context context) {
        return NetManager.getInstance(context);
    }

    private static Builder builder() {
        return new Connectivity.Builder();
    }

    public static Builder available(boolean isAvailable) {
        return builder().available(isAvailable);
    }

    public boolean available() {
        return isAvailable;
    }

    public static Builder roaming(boolean isRoaming) {
        return builder().roaming(isRoaming);
    }

    public boolean roaming() {
        return isRoaming;
    }

    public NetworkState getNetworkState() {
        return networkState;
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) {
            return true;
        }
        if (object == null || getClass() != object.getClass()) {
            return false;
        }

        Connectivity that = (Connectivity) object;

        if (isAvailable != that.isAvailable) {
            return false;
        }
        if (isRoaming != that.isRoaming) {
            return false;
        }
        return Objects.equals(networkState, that.networkState);
    }

    @Override
    public int hashCode() {
        int result = networkState.hashCode();
        result = 31 * result + (isAvailable ? 1 : 0);
        result = 31 * result + (isRoaming ? 1 : 0);
        return result;
    }

    public static final class Builder {
        private boolean isAvailable = false; // NOPMD

        private boolean isRoaming = false; // NOPMD

        private NetworkState networkState = new NetworkState();

        public Builder available(boolean available) {
            this.isAvailable = available;
            return this;
        }

        public Builder roaming(boolean roaming) {
            this.isRoaming = roaming;
            return this;
        }

        public Builder networkState(NetworkState state) {
            this.networkState = state;
            if (state.getNetworkCapabilities() != null) {
                this.isAvailable = state.getNetworkCapabilities().hasCap(NetCapabilities.NET_CAPABILITY_INTERNET);
                this.isRoaming =
                    !state.getNetworkCapabilities().hasCap(NetCapabilities.NET_CAPABILITY_NOT_ROAMING);
            }
            return this;
        }

        public Connectivity build() {
            Connectivity connectivity = new Connectivity(this);
            Log.error(LOG_TAG, toString());
            return connectivity;
        }
    }
}
